#include "byte_string.h"
#include "events/common_log.h"
#include <stdarg.h>
#include <string.h>

ByteString::ByteString()
    : mString(nullptr), mLen(0)
{    
}

ByteString::ByteString(const char *str, int size)
    : mString((char *)str), mLen((size>=0) ? size : (str ? strlen(str) : 0))
{
}

ByteString::ByteString(const char *str)
    : mString((char *)str), mLen(str ? strlen(str) : 0)
{
}

ByteString::ByteString(int size, int)
    : mString(NULL)
    , mLen(size)
{
    if (size > 0)
    {
        mString = new char[size];
        mString[0] = 0;
    }
}

void ByteString::clear()
{
    if (mString && mLen > 0)
    {
        // GEN_Printf(LOG_DEBUG, "clear: %s", mString);
        delete [] mString;
    }
    mString = nullptr;
    mLen = 0;
}

ByteString ByteString::allocString(const ByteString &bstr)
{
    if (!bstr.empty())
    {
        char *s = new char [bstr.size() + 1];
        memcpy(s, bstr.string(), bstr.size());
        s[bstr.size()] = '\0';
        return ByteString(s, bstr.size());
    } else
    {
        // GEN_Printf(LOG_WARN, "string is invalid !!!");
        return ByteString();
    }
}

#define LONG_LEN 24
ByteString ByteString::allocLong(long i)
{
    char buffer[64];
    int len = snprintf(buffer, 63, "%ld", i);

    return allocString(ByteString(buffer, len));
}

ByteString ByteString::allocDouble(double i)
{
    char buffer[64];
    int len = snprintf(buffer, 63, "%g", i);

    return allocString(ByteString(buffer, len));
}

ByteString ByteString::numToString(bool i)
{
    return i ? "true" : "false";
}

static char _g_string_buffer[64];
ByteString ByteString::numToString(long i)
{
    int ret = snprintf(_g_string_buffer, 63, "%ld", i);
    return ByteString(_g_string_buffer, ret);
}

ByteString ByteString::numToString(unsigned long i)
{
    int ret = snprintf(_g_string_buffer, 63, "%lu", i);
    return ByteString(_g_string_buffer, ret);
}

ByteString ByteString::numToString(long long i)
{
    int ret = snprintf(_g_string_buffer, 63, "%lld", i);
    return ByteString(_g_string_buffer, ret);
}

ByteString ByteString::numToString(unsigned long long i)
{
    int ret = snprintf(_g_string_buffer, 63, "%llu", i);
    return ByteString(_g_string_buffer, ret);
}

ByteString ByteString::numToString(float i, const char *fmt)
{
    int ret = snprintf(_g_string_buffer, 63, fmt, i);
    return ByteString(_g_string_buffer, ret);
}

ByteString ByteString::numToString(double i, const char *fmt)
{
    int ret = snprintf(_g_string_buffer, 63, fmt, i);
    return ByteString(_g_string_buffer, ret);
}

static size_t _sf_strlcpy (char *dst, const char *src, size_t size)
{
    const char *old = src;

    /* Copy as many bytes as will fit */
    if (size)
    {
        while (--size)
        {
            if (!(*dst++ = *src++))
            {
                return src - old - 1;
            }
        }

        *dst = 0;
    }

    while (*src++);
    return src - old - 1;
}

ByteString ByteString::concatStrings(const ByteString &first, const char *str0, ...)
{
    va_list args;
    const char *arg;
    size_t length = first.size(), pos = first.size();
    char *s;
    if(!str0 || first.empty()) return first;

    va_start (args, str0);
    for (arg = str0; arg; arg = va_arg (args, const char *))
    {
        length += strlen(arg);
    }
    va_end (args);

    s = new char[length + 1];

    //GEN_Printf(LOG_DEBUG, "[%s], size: %d, length: %d", first.string(), first.size(), length);
    strncpy(s, first.string(), first.size());

    va_start (args, str0);
    for (arg = str0; arg; arg = va_arg (args, const char *))
    {
        pos += _sf_strlcpy(s + pos, arg, length - pos + 1);
    }
    va_end (args);

    return ByteString(s, length);

}

bool ByteString::operator==(const ByteString &str) const
{
    if (str.mString == mString) return true;
    if (!str.mString || !mString) return false;
    if (str.mLen != mLen) return false;    
    return 0 == strncmp(str.mString, mString, mLen);
}

bool ByteString::operator!=(const ByteString &str) const
{
    if (str.mString == mString) return false;
    if (!str.mString || !mString) return true;
    if (str.mLen != mLen) return true;
    return strncmp(str.mString, mString, mLen);
}

bool ByteString::operator>(const ByteString &str) const
{
    if (str.mString == mString) return false;
    if (!str.mString) return true;
    if (!mString) return false;

    return strcmp(mString, str.mString) > 0 ? true : false ;
}

bool ByteString::operator<(const ByteString &str) const
{
    if (str.mString == mString) return false;
    if (!str.mString) return false;
    if (!mString) return true;

    return strcmp(mString, str.mString) < 0 ? true : false ;
}

int ByteString::compare(const ByteString &str)
{
    if (str.mString == mString) return 0;
    if (!str.mString) return 1;
    if (!mString) return -1;

    return strcmp(mString, str.mString);
}

int ByteString::ncompare(const ByteString &str)
{
    if (str.mString == mString) return 0;
    if (!str.mString) return 1;
    if (!mString) return -1;

    return strncmp(mString, str.mString, str.size());
}

int ByteString::find(const ByteString &str, int pos)
{
    if (str.empty() || this->empty() || str.size() > this->size() || (uint)pos >= (uint)this->size()) return -1;

#if 0
    char *res = strstr(mString + pos, str.string());
    if (res)
    {
        return (int)(res - mString) + pos;
    }
#else
    const char *s1     = mString + pos;
    const char *s1_end = mString + mLen;
    const char *s2     = str.string();
    const char *s2_end = s2 + str.size();

    for (; s1 < s1_end; ++s1) /*每次后移s1的位置，在新的位置进行下一次匹配*/
    {
        while ((*s1 != *s2) && (s1 < s1_end))
        {
            ++s1; /*在s1中找到和s2第一个字符匹配的位置*/
        }

        if (s1 == s1_end) /*如果找不到，说明s1现在的位置不匹配，退出循环进行下一次匹配*/
        {
            break;
        } else /*如果找到和s2第一个字符匹配的位置，开始逐个匹配s2后面的字符*/
        {
            const char *sc1, *sc2;
            for (sc1 = s1, sc2 = s2; sc1 < s1_end; ++sc1, ++sc2)
            {
                if (sc2 == s2_end) /*如果匹配完毕，返回s1此时的位置*/
                {
                    return (s1 - mString) + pos;
                } else if (*sc1 != *sc2) /*如果后面有一个字符不匹配，说明s1现在的位置不匹配，退出循环进行下一次匹配*/
                {
                    break;
                }
            }
            // 如果匹配的字串都在末尾的情况
            if (sc2 == s2_end) /*如果匹配完毕，返回s1此时的位置*/
            {
                return (s1 - mString) + pos;
            }
        }
    }
#endif
    return -1;
}

int ByteString::find(int ch, int pos)
{
    if (0 == ch || this->empty() || pos >= this->size()) return -1;

    for (int i = pos; i < mLen; ++i)
    {
        if (mString[i] == ch) return i;
    }
    return -1;
}

int ByteString::rfind(const ByteString &str, int pos)
{
    int rel_pos = pos < 0 ? mLen + pos : pos;
    if (str.empty() || this->empty() || str.size() > this->size() || rel_pos >= this->size()) return -1;

    const char *s1     = mString + rel_pos;
    const char *s1_end = mString;

    const char *s2_end = str.string();
    const char *s2     = s2_end + str.size() - 1;

    for (; s1 >= s1_end; --s1) /*每次后移s1的位置，在新的位置进行下一次匹配*/
    {
        while ((*s1 != *s2) && (s1 >= s1_end))
        {
            --s1; /*在s1中找到和s2第一个字符匹配的位置*/
        }

        if (s1 < s1_end) /*如果找不到，说明s1现在的位置不匹配，退出循环进行下一次匹配*/
        {
            break;
        } else /*如果找到和s2第一个字符匹配的位置，开始逐个匹配s2后面的字符*/
        {
            const char *sc1, *sc2;
            for (sc1 = s1, sc2 = s2; sc1 >= s1_end; --sc1, --sc2)
            {
                if (sc2 < s2_end) /*如果匹配完毕，返回s1此时的位置*/
                {
                    return (s1 - mString) - str.size()+1;
                } else if (*sc1 != *sc2) /*如果后面有一个字符不匹配，说明s1现在的位置不匹配，退出循环进行下一次匹配*/
                {
                    break;
                }
            }
            // 解决匹配的字串在起始位置的异常
            if (sc2 < s2_end) /*如果匹配完毕，返回s1此时的位置*/
            {
                return (s1 - mString) - str.size()+1;
            }
        }
    }

    return -1;
}

int ByteString::rfind(int ch, int pos)
{
    if (0 == ch || this->empty() || pos >= this->size()) return -1;

    for (int i = mLen-1; i > pos; --i)
    {
        if (mString[i] == ch) return i;
    }
    return -1;
}

static void _mix(unsigned long &a, unsigned long &b, unsigned long &c)
{
    a -= b; a -= c; a ^= (c >> 13);
    b -= c; b -= a; b ^= (a << 8);
    c -= a; c -= b; c ^= (b >> 13);
    a -= b; a -= c; a ^= (c >> 12);
    b -= c; b -= a; b ^= (a << 16);
    c -= a; c -= b; c ^= (b >> 5);
    a -= b; a -= c; a ^= (c >> 3);
    b -= c; b -= a; b ^= (a << 10);
    c -= a; c -= b; c ^= (b >> 15);
}
/*
/home/chenmeng/workspace/rv1109/rv1109Project/srcLibrary/solfFramework/util/byte_string.cpp:259: 警告： this statement may fall through [-Wimplicit-fallthrough=]
     case 11: hashv += ((unsigned char)_hj_key[10] << 24);
              ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
// -Wimplicit-fallthrough=
//__attribute__((_fallthrough))

//#parama disable(Warnning No)
//#pragma warning(disable:4507)
//#pragma warning(implicit-fallthrough)
#define Q_FALLTHROUGH() __attribute__((fallthrough))
//#define Q_FALLTHROUGH()
unsigned long ByteString::genHashValue() const
{
    SF_ASSERT(!empty());
    unsigned long _hj_i, _hj_j, _hj_k;
    char *_hj_key   = this->string();
    unsigned long keylen = this->size();
    unsigned long hashv = 0xfeedbeef;

    _hj_i = _hj_j = 0x9e3779b9;
    _hj_k = keylen;
    while (_hj_k >= 12)
    {
        _hj_i += (_hj_key[0] + ((unsigned char)_hj_key[1] << 8)
                + ((unsigned char)_hj_key[2] << 16)
                + ((unsigned char)_hj_key[3] << 24));
        _hj_j += (_hj_key[4] + ((unsigned char)_hj_key[5] << 8)
                + ((unsigned char)_hj_key[6] << 16)
                + ((unsigned char)_hj_key[7] << 24));
        hashv += (_hj_key[8] + ((unsigned char)_hj_key[9] << 8)
                + ((unsigned char)_hj_key[10] << 16)
                + ((unsigned char)_hj_key[11] << 24));

        _mix(_hj_i, _hj_j, hashv);

        _hj_key += 12;
        _hj_k -= 12;
    }

    hashv += keylen;
    switch (_hj_k)
    {
    case 11: hashv += ((unsigned char)_hj_key[10] << 24); Q_FALLTHROUGH();
    case 10: hashv += ((unsigned char)_hj_key[9] << 16); Q_FALLTHROUGH();
    case 9:  hashv += ((unsigned char)_hj_key[8] << 8); Q_FALLTHROUGH();
    case 8:  _hj_j += ((unsigned char)_hj_key[7] << 24); Q_FALLTHROUGH();
    case 7:  _hj_j += ((unsigned char)_hj_key[6] << 16); Q_FALLTHROUGH();
    case 6:  _hj_j += ((unsigned char)_hj_key[5] << 8); Q_FALLTHROUGH();
    case 5:  _hj_j += _hj_key[4]; Q_FALLTHROUGH();
    case 4:  _hj_i += ((unsigned char)_hj_key[3] << 24); Q_FALLTHROUGH();
    case 3:  _hj_i += ((unsigned char)_hj_key[2] << 16); Q_FALLTHROUGH();
    case 2:  _hj_i += ((unsigned char)_hj_key[1] << 8); Q_FALLTHROUGH();
    case 1:  _hj_i += _hj_key[0];
    }

    _mix(_hj_i, _hj_j, hashv);

    return hashv;
}

int ByteString::toInt(int def)
{
    return empty() ? def : atoi(mString);
}

int ByteString::toUInt(unsigned int def) const
{
    return empty() ? def : strtoul(mString, NULL, 10);
}

bool ByteString::toBool(bool def)
{
    return empty() ? def : ((0 == strcmp(mString, "1")
                             || 0 == strcasecmp(mString, "true")) ? true : false);
}

double ByteString::toDouble(double def)
{
    return empty() ? def : strtod(mString, NULL);
}

long ByteString::toLong(long def)
{
    return empty() ? def : strtol(mString, NULL, 10);
}

unsigned long ByteString::toULong(unsigned long def)
{
    return empty() ? def : strtoul(mString, NULL, 10);
}

long long ByteString::toULongLong(long long def)
{
    return empty() ? def : strtoll(mString, NULL, 10);
}

unsigned long long ByteString::toLongLong(unsigned long long def)
{
    return empty() ? def : strtoull(mString, NULL, 10);
}

void ByteString::append(const ByteString &str)
{
    char *newStr = new char[mLen + str.size() + 1];

    if (isValid())
    {
        memcpy(newStr, mString, mLen);
        memcpy(newStr + mLen, str.string(), str.size());

        delete [] mString;
        mString = newStr;
        mLen   += str.size();
        mString[mLen] = '\0';
    } else
    {
        memcpy(newStr, str.string(), str.size());

        mString = newStr;
        mLen    = str.size();
        mString[mLen] = '\0';
    }
}

void ByteString::realloc(int size)
{
    if (size > mLen)
    {
        char *tmp = new char [size];
        if (isValid())
        {
            memcpy(tmp, mString, mLen);
            delete mString;
        }

        mString = tmp;
    }
}

void ByteString::resize(int size)
{
    if (size >=0 && size < mLen)
    {
        mString[size] = '\0';
        mLen          = size;
    }
}

void ByteString::swap(ByteString &str)
{
    char *string = mString;
    int   len    = mLen;

    mString = str.string();
    mLen    = str.size();

    str = ByteString(string, len);
}

/**
 * @brief HttpUtil::urlDecoding
 * @param query [in] 网络地址, 字符指向的地址时可以操作的
 * @param percent
 * @details 把‘%’表示的字符，替换的回来
 *  例如：%e9%99%88%e7%8c%9b 转成："陈猛"
 */
void ByteString::urlDecoding(ByteString &query, char percent)
{
    char *data = query.string();
    const char *inputPtr = query.string();

    int i = 0;
    int len = query.size();
    int outlen = 0;
    int a, b;
    char c;

    while (i < len)
    {
        c = inputPtr[i];
        if (c == percent && i + 2 < len)
        {
            a = inputPtr[++i];
            b = inputPtr[++i];

            if (a >= '0' && a <= '9') a -= '0';
            else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
            else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;

            if (b >= '0' && b <= '9') b -= '0';
            else if (b >= 'a' && b <= 'f') b  = b - 'a' + 10;
            else if (b >= 'A' && b <= 'F') b  = b - 'A' + 10;

            data[outlen] = (char)((a << 4) | b);
        } else
        {
            data[outlen] = c;
        }

        ++i;
        ++outlen;
    }

    if (outlen != len)
    {
        query.resize(outlen);
    }
}

int ByteString::getUtf8Size(const unsigned char pInput)
{
    unsigned char c = pInput;
    if(c< 0x80) return 1;
    else if(c>=0x80 && c<0xC0) return -1;
    else if(c>=0xC0 && c<0xE0) return 2;
    else if(c>=0xE0 && c<0xF0) return 3;
    else if(c>=0xF0 && c<0xF8) return 4;
    else if(c>=0xF8 && c<0xFC) return 5;
    else return 6;//if(c>=0xFC) return 6;
}

int ByteString::validUtf8Length(const char *data, int len)
{
    int valid_len = 0;
    for (int i = 0; i < len;)
    {
        int utf8len = getUtf8Size(data[i]);
        if (utf8len < 1) break;
        if (valid_len + utf8len > len) break;

        if (2 == utf8len && ( (data[i+1] & 0xC0) != 0x80 ))
            break;
        else if (3 == utf8len && ( ((data[i+1] & 0xC0) != 0x80)
                                   || ((data[i+2] & 0xC0) != 0x80) ))
            break;
        else if (4 == utf8len && ( ((data[i+1] & 0xC0) != 0x80)
                                   || ((data[i+2] & 0xC0) != 0x80)
                                   || ((data[i+3] & 0xC0) != 0x80) ))
            break;
        else if (5 == utf8len && ( ((data[i+1] & 0xC0) != 0x80)
                                   || ((data[i+2] & 0xC0) != 0x80)
                                   || ((data[i+3] & 0xC0) != 0x80)
                                   || ((data[i+4] & 0xC0) != 0x80) ))
            break;
        else if (6 == utf8len && ( ((data[i+1] & 0xC0) != 0x80)
                                   || ((data[i+2] & 0xC0) != 0x80)
                                   || ((data[i+3] & 0xC0) != 0x80)
                                   || ((data[i+4] & 0xC0) != 0x80)
                                   || ((data[i+5] & 0xC0) != 0x80) ))
            break;

        valid_len += utf8len;
        i         += utf8len;
    }

    return valid_len;
}

/**
 * @brief HttpUtil::urlEncoding
 * @param query [in] 网络地址, 字符指向的地址时可以操作的
 * @param result [out] 返回的转换后的数据
 * @param percent
 * @details 把‘%’表示的字符，替换的回来
 *  例如："陈猛" 转成： %e9%99%88%e7%8c%9b
 * assci字符 0 ～ 31 之间的字符都要转译
 * 32 ~ 39 = 00000010 --0x02
 * 40 ~ 47 = 00110111 --0x37
 * 48 ~ 55 = 11111111 --0xFF
 * 56 ~ 63 = 11100101 --0xE5
 * 64 ~ 71 = 11111111 --0xFF
 * 72 ~ 79 = 11111111 --0xFF
 * 80 ~ 87 = 11111111 --0xFF
 * 88 ~ 95 = 11100000 --0xE0
 * 96 ~103 = 01111111 --0x7F
 * 104~111 = 11111111 --0xFF
 * 112~119 = 11111111 --0xFF
 * 120~127 = 11100000 --0xE0
 */
void ByteString::urlEncoding(const ByteString &query, ByteString &result, char percent)
{
    char *data = new char[query.size() * 3]; // 按照最大长度分配
    const char *inputPtr = query.string();
    static const char *pattern = "0123456789abcdef";
    static uint8_t authBit[16]={0,    0,    0,    0,    //前32位都必须转译
                                0x02, 0x37, 0xFF, 0xE5,
                                0xFF, 0xFF, 0xFF, 0xE0,
                                0x7F, 0xFF, 0xFF, 0xE0};

    int i = 0;
    int len = query.size();
    int outlen = 0;
    unsigned char c;

    while (i < len)
    {
        c = (unsigned char)inputPtr[i];
        //GEN_Printf(LOG_DEBUG, "[%c] %d - [%d, %d]", c, (unsigned char)c, c >> 3, (c & 0x7));
        if (!(c & 0x80) && (authBit[c >> 3] & (0x80 >> (c & 0x7))))
        {
            data[outlen++] = c;
        } else
        {
            data[outlen++] = percent;
            data[outlen++] = pattern[(c >> 4) & 0xF];
            data[outlen++] = pattern[c  & 0xF];
        }
        ++i;
    }
    data[outlen] = '\0';

    result.clear();
    result = ByteString(data, outlen);
}

ByteStringList::ByteStringList(const ByteString &str, char spilt)
{
    const char *p     = str.string();
    const char *end   = p + str.size();

    ByteString line((char *)p, 0);

    while (p < end)
    {
        if (*p == spilt)
        {
            line.mLen = p - line.mString;

            // GEN_Printf(LOG_DEBUG, "pos=%d, size=%d", line.mString - str.string(), line.mLen);
            this->push_back(line);

            while (p < end && (*p == spilt || *p == ' ' || *p == '\t')) ++p;

            line.mLen    = 0;
            line.mString = (char *)p;
            ++p;
        } else
        {
            ++p;
        }
    }

    line.mLen = p - line.mString;
    if (line.mLen > 0)
    {
        this->push_back(line);
    }
}

bool ByteStringList::contain(const ByteString &str)
{
    for (ByteString &f : *this)
    {
        if (f == str)
        {
            return true;
        }
    }
    return false;
}
